package article

import (
	"10apiserver/common/db"
	"strings"
	"time"

	"github.com/jinzhu/gorm"
)

type ArticleInfo struct {
	ID        int64     `gorm:"primary_key;AUTO_INCREMENT;column:ID" json:"id"`
	FilePath  string    `gorm:"column:FilePath" json:"filePath" binding:"required"`
	Title     string    `gorm:"column:Title" json:"title" binding:"required"`
	Preview   string    `gorm:"column:Preview" json:"preview" binding:"required"`
	CreatedAt time.Time `gorm:"column:CreatedAt" json:"createdAt"`
	UpdatedAt time.Time `gorm:"column:UpdatedAt" json:"updatedAt"`
	ReadCount int64     `gorm:"column:ReadCount" json:"readCount"`
	Tags      []string  `gorm:"-" json:"tags" binding:"required"`
}

func (artInfo *ArticleInfo) TableName() string {
	return "articles"
}

func (artInfo *ArticleInfo) Create() error {
	tx := database.DB.Begin()

	err := tx.Create(artInfo).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	for _, aTag := range artInfo.Tags {
		var tagInfo TagInfo
		err = tx.Where(TagInfo{Tag: strings.ToLower(aTag)}).FirstOrCreate(&tagInfo).Error
		if err != nil {
			tx.Rollback()
			return err
		}

		err = tx.Create(&TagArticleInfo{TagID: tagInfo.ID, ArticleID: artInfo.ID}).Error
		if err != nil {
			tx.Rollback()
			return err
		}

	}

	tx.Commit()

	return nil
}

func (artInfo *ArticleInfo) Update() error {
	return database.DB.Save(&artInfo).Error
}

func (artInfo *ArticleInfo) Delete() error {

	tx := database.DB.Begin()

	err := tx.Delete(&artInfo).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	err = tx.Where("ArticleID = ?", &artInfo.ID).Delete(TagArticleInfo{}).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()

	return nil
}

func (artInfo *ArticleInfo) DeleteByPath() error {

	tx := database.DB.Begin()

	err := database.DB.Where("FilePath = ?", &artInfo.FilePath).Delete(ArticleInfo{}).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	err = tx.Where("ArticleID = ?", &artInfo.ID).Delete(TagArticleInfo{}).Error
	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()

	return nil
}

func (artInfo *ArticleInfo) IncReadCount() error {
	return database.DB.Model(&artInfo).UpdateColumn("ReadCount", gorm.Expr("ReadCount + ?", 1)).Error
}

func GetByID(id int64) (*ArticleInfo, error) {
	var artInfo ArticleInfo
	if err := database.DB.First(&artInfo, id).Error; err != nil {
		return nil, err
	} else {
		return &artInfo, nil
	}
}

func GetByPath(filePath string) (*ArticleInfo, error) {
	var artInfo ArticleInfo
	if err := database.DB.Where("FilePath = ?", filePath).First(&artInfo).Error; err != nil {
		return nil, err
	} else {
		return &artInfo, nil
	}
}

func ListArticles(tag string, offset, limit int) (*ArticlesResult, error) {
	sqlBase := "FROM articles LEFT JOIN tag_article ON articles.ID = tag_article.ArticleID LEFT JOIN tags ON tag_article.TagID = tags.ID  WHERE tags.Tag like '%" + tag + "%' GROUP BY articles.ID"
	var totalCount int

	sqlTotalCount := "SELECT COUNT(*) totalCount from (SELECT articles.ID   " + sqlBase + " ) a "
	rows, err := database.DB.Raw(sqlTotalCount).Rows()
	if err != nil {
		return nil, err
	}

	for rows.Next() {
		rows.Scan(&totalCount)
	}

	rows.Close()
	if totalCount == 0 {
		return &ArticlesResult{}, nil
	}

	sql := "SELECT articles.*,GROUP_CONCAT(tags.Tag) as Tags " + sqlBase + " ORDER BY articles.UpdatedAt desc LIMIT ? OFFSET ?"
	// sql := "SELECT articles.* " + sqlBase + " LIMIT ? OFFSET ?"
	rows, err = database.DB.Raw(sql, limit, offset).Rows()
	defer rows.Close()
	if err != nil {
		return nil, err
	}

	var articles []*ArticleInfo
	for rows.Next() {
		var art ArticleInfo
		var strTags string
		rows.Scan(&art.ID, &art.FilePath, &art.Title, &art.Preview, &art.CreatedAt, &art.UpdatedAt, &art.ReadCount, &strTags)
		art.Tags = strings.Split(strTags, ",")
		//rows.Scan(&art)
		articles = append(articles, &art)
	}

	var artResult ArticlesResult
	artResult.ArticleList = articles
	artResult.PageCount = len(articles)
	artResult.TotalCount = totalCount

	return &artResult, nil
}
